using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Windows.Forms;

namespace ICP_MS.Plugin.Tune;

public class AutoTuneExperiment
{
	public class TuneIsotope
	{
		public int Id { get; set; }

		public string Symbol { get; set; }

		public double Mass { get; set; }

		public int Dwell { get; set; }

		public double Result { get; set; }
	}

	public class TuneRatio
	{
		public int Id { get; set; }

		public TuneIsotope Numerator { get; set; }

		public TuneIsotope Denominator { get; set; }

		public int Dwell { get; set; }
	}

	public class DeviceCondition
	{
		public int Id { get; set; }

		public bool Selected { get; set; }

		public bool Force { get; set; }

		public string Device { get; set; }

		public double MinValue { get; set; }

		public double MaxValue { get; set; }

		public double DefaultValue { get; set; }

		public double MinLimit { get; set; }

		public double MaxLimit { get; set; }

		public double ReadErr { get; set; }

		public double FinishErr { get; set; }

		public double Step { get; set; }

		public double BestValue { get; set; }

		public double BestResult { get; set; }

		public bool Used { get; set; }

		public bool Related { get; set; }

		public int Coe { get; set; }

		public bool Finished { get; set; }

		public bool FirstComp { get; set; }

		public double DeviceSets { get; set; }

		public DeviceCondition Clone()
		{
			DeviceCondition device = new DeviceCondition();
			device.Id = Id;
			device.Device = Device;
			device.Selected = Selected;
			device.Force = Force;
			device.MinValue = MinValue;
			device.MaxValue = MaxValue;
			device.DefaultValue = DefaultValue;
			device.ReadErr = ReadErr;
			device.FinishErr = FinishErr;
			device.Step = Step;
			device.Related = Related;
			device.Coe = Coe;
			device.MinLimit = MinLimit;
			device.MaxLimit = MaxLimit;
			device.BestResult = BestResult;
			device.FirstComp = device.FirstComp;
			return device;
		}

		public void Copy(DeviceCondition dev)
		{
			if (Id == dev.Id)
			{
				Force = dev.Force;
				MinValue = dev.MinValue;
				MaxValue = dev.MaxValue;
				MinLimit = dev.MinLimit;
				MaxLimit = dev.MaxLimit;
				DefaultValue = dev.DefaultValue;
				Step = dev.Step;
				ReadErr = dev.ReadErr;
				FinishErr = dev.FinishErr;
			}
		}
	}

	public class ParamConditon
	{
		public int Id { get; set; }

		public string Symbol { get; set; }

		public TuneIsotope Isotope { get; set; }

		public TuneRatio Ratio { get; set; }

		public int Type { get; set; }

		public double Limit { get; set; }

		public double Result { get; set; }

		public bool Pass { get; set; }

		public double BestResult { get; set; }

		public ParamConditon Clone()
		{
			ParamConditon param = new ParamConditon();
			param.Id = Id;
			param.Symbol = Symbol;
			param.Isotope = Isotope;
			param.Ratio = Ratio;
			param.Type = Type;
			param.Limit = Limit;
			return param;
		}
	}

	public class TuneStage
	{
		public int Index { get; set; }

		public bool Used { get; set; }

		public string StageName { get; set; }

		public int Iterations { get; set; }

		public int Sweeps { get; set; }

		public List<DeviceCondition> Devices { get; set; }

		public List<ParamConditon> Params { get; set; }

		public bool Selected { get; set; }

		public bool Related { get; set; }

		public bool Finished { get; set; }

		public void UpdateDevice(DeviceCondition dev)
		{
			foreach (DeviceCondition stageDev in Devices)
			{
				if (stageDev.Id == dev.Id)
				{
					stageDev.Copy(dev);
				}
			}
		}
	}

	public class StageResult1
	{
		public double Y { get; set; }

		public double X { get; set; }

		public double result { get; set; }
	}

	public class StageResult2
	{
		public double CarrierGas { get; set; }

		public double Power { get; set; }

		public double Result { get; set; }
	}

	public class StageResult3
	{
		public double Ext { get; set; }

		public double L1 { get; set; }

		public double L2 { get; set; }

		public double L3 { get; set; }

		public double result { get; set; }
	}

	public class StageResult4
	{
		public double Focus { get; set; }

		public double D1 { get; set; }

		public double D2 { get; set; }

		public double DA { get; set; }

		public double QE { get; set; }

		public double Result { get; set; }
	}

	public List<List<double>> StageDeviceResult = new List<List<double>>();

	private int currentIndex = 0;

	public bool bSkipped = false;

	private List<double> massX = new List<double>();

	private Thread threadTune = null;

	private AutoResetEvent scanEvent = new AutoResetEvent(initialState: false);

	private double BestResult = -1.0;

	public List<TuneIsotope> Isotopes { get; set; }

	public List<TuneRatio> Ratios { get; set; }

	public List<DeviceCondition> Devices { get; set; }

	public List<ParamConditon> Params { get; set; }

	public List<TuneStage> Stages { get; set; }

	public TuneStage CurrentStage
	{
		get
		{
			if (currentIndex < 0)
			{
				return null;
			}
			if (currentIndex == Stages.Count)
			{
				TuneStage stage = new TuneStage();
				stage.Used = false;
				stage.Params = new List<ParamConditon>();
				stage.Devices = new List<DeviceCondition>();
				stage.Sweeps = 10;
				stage.Iterations = 1;
				stage.Selected = true;
				stage.Related = false;
				stage.StageName = $"Stage - {currentIndex + 1}";
				UpdateTuneStage(stage);
				Stages.Add(stage);
			}
			return Stages[currentIndex];
		}
	}

	public TuneStage FirstStage
	{
		get
		{
			currentIndex = 0;
			return CurrentStage;
		}
	}

	public TuneStage LastStage
	{
		get
		{
			currentIndex = Stages.Count - 1;
			return CurrentStage;
		}
	}

	public bool IsFirstStage => currentIndex == 0;

	public string Name { get; set; }

	public string Description { get; set; }

	public string Solution { get; set; }

	public bool isTuning { get; set; }

	public double StageIndex { get; set; }

	public bool TuneSucceed { get; set; }

	public event EventHandler EventTuneFinish;

	public event EventHandler<MsgEventArgs> EventTuneMsg;

	public event EventHandler<PointEventMsg> EventPointMsg;

	public void SelectLastStage()
	{
		currentIndex--;
	}

	public void SelectNextStage()
	{
		currentIndex++;
	}

	public bool CheckFrontStage()
	{
		for (int i = currentIndex; i >= 0; i--)
		{
			if (Stages[i].Used)
			{
				return true;
			}
		}
		return false;
	}

	public bool CheckRearStage()
	{
		for (int i = currentIndex; i < Stages.Count; i++)
		{
			if (Stages[i].Used)
			{
				return true;
			}
		}
		return false;
	}

	public bool RemoveCurrentStage(bool direction)
	{
		Stages.RemoveAt(currentIndex);
		currentIndex = (direction ? (currentIndex + 1) : (currentIndex - 1));
		return false;
	}

	public AutoTuneExperiment()
	{
		Isotopes = new List<TuneIsotope>();
		Ratios = new List<TuneRatio>();
		Params = new List<ParamConditon>();
		Devices = new List<DeviceCondition>();
		Stages = new List<TuneStage>();
	}

	public void InitTuneDevices()
	{
		if (Devices == null || Devices.Count == 0)
		{
			Devices.Add(new DeviceCondition
			{
				Id = 0,
				Device = Lang.Txt("FormIgnite.XPosition.Text"),
				Force = true,
				MaxValue = 16.0,
				MinValue = 2.0,
				DefaultValue = 5.0,
				MinLimit = 1.0,
				MaxLimit = 20.0,
				Step = 0.1,
				ReadErr = 0.05,
				FinishErr = 0.05,
				Coe = 1
			});
			Devices.Add(new DeviceCondition
			{
				Id = 1,
				Device = Lang.Txt("FormIgnite.YPosition.Text "),
				Force = true,
				MaxValue = 16.0,
				MinValue = 2.0,
				DefaultValue = 5.0,
				MinLimit = 1.0,
				MaxLimit = 20.0,
				Step = 0.1,
				ReadErr = 0.05,
				FinishErr = 0.05,
				Coe = 1
			});
			Devices.Add(new DeviceCondition
			{
				Id = 17,
				Device = Lang.Txt("AddFormQuad.Power"),
				Force = true,
				MaxValue = 1800.0,
				MinValue = 1200.0,
				DefaultValue = 1400.0,
				MinLimit = 100.0,
				MaxLimit = 2000.0,
				Step = 10.0,
				ReadErr = 50.0,
				FinishErr = 5.0,
				Coe = 1
			});
			Devices.Add(new DeviceCondition
			{
				Id = 13,
				Device = Lang.Txt("FormIgnite.CarrierGas.Text "),
				Force = true,
				MaxValue = 1.5,
				MinValue = 0.9,
				DefaultValue = 1.1,
				MinLimit = 0.8,
				MaxLimit = 1.5,
				Step = 0.01,
				ReadErr = 0.1,
				FinishErr = 0.01,
				Coe = 1
			});
			Devices.Add(new DeviceCondition
			{
				Id = 2,
				Device = Lang.Txt("FormIgnite.ZPosition.Text "),
				Force = true,
				MaxValue = 16.0,
				MinValue = 2.0,
				DefaultValue = 5.0,
				MinLimit = 2.0,
				MaxLimit = 16.0,
				Step = 0.1,
				ReadErr = 0.05,
				FinishErr = 0.05,
				Coe = 1
			});
			Devices.Add(new DeviceCondition
			{
				Id = 3,
				Device = Lang.Txt("Tune.ExtractionLens"),
				Force = true,
				MaxValue = -900.0,
				MinValue = -300.0,
				DefaultValue = -500.0,
				MinLimit = -200.0,
				MaxLimit = -1000.0,
				Step = 50.0,
				ReadErr = 0.5,
				FinishErr = 10.0,
				Coe = -1
			});
			Devices.Add(new DeviceCondition
			{
				Id = 4,
				Device = Lang.Txt("Tune.Lens") + "(L1)",
				Force = true,
				MaxValue = -1600.0,
				MinValue = -800.0,
				DefaultValue = -1200.0,
				MinLimit = -500.0,
				MaxLimit = -1900.0,
				Step = 50.0,
				ReadErr = 0.5,
				FinishErr = 5.0,
				Coe = -1
			});
			Devices.Add(new DeviceCondition
			{
				Id = 5,
				Device = Lang.Txt("Tune.Lens") + "(L2)",
				Force = true,
				MaxValue = -100.0,
				MinValue = -60.0,
				DefaultValue = -80.0,
				MinLimit = -20.0,
				MaxLimit = -200.0,
				Step = 5.0,
				ReadErr = 0.5,
				FinishErr = 1.0,
				Coe = -1
			});
			Devices.Add(new DeviceCondition
			{
				Id = 11,
				Device = Lang.Txt("Tune.Lens") + "(L3)",
				Force = true,
				MaxValue = -200.0,
				MinValue = -150.0,
				DefaultValue = -180.0,
				MinLimit = -50.0,
				MaxLimit = -100.0,
				Step = 5.0,
				ReadErr = 0.5,
				FinishErr = 5.0,
				Coe = -1
			});
			Devices.Add(new DeviceCondition
			{
				Id = 6,
				Device = Lang.Txt("Tune.Focus"),
				Force = true,
				MaxValue = 25.0,
				MinValue = 8.0,
				DefaultValue = 13.5,
				MinLimit = 5.0,
				MaxLimit = 30.0,
				Step = 0.5,
				ReadErr = 0.5,
				FinishErr = 0.5,
				Coe = 1
			});
			Devices.Add(new DeviceCondition
			{
				Id = 9,
				Device = Lang.Txt("Tune.QE"),
				Force = true,
				MaxValue = -60.0,
				MinValue = -10.0,
				DefaultValue = -35.0,
				MinLimit = -1.0,
				MaxLimit = -200.0,
				Step = 1.0,
				ReadErr = 0.5,
				FinishErr = 0.5,
				Coe = -1
			});
			Devices.Add(new DeviceCondition
			{
				Id = 7,
				Device = Lang.Txt("Tune.D1"),
				Force = true,
				MaxValue = -200.0,
				MinValue = -10.0,
				DefaultValue = -150.0,
				MinLimit = -10.0,
				MaxLimit = -200.0,
				Step = 10.0,
				ReadErr = 0.5,
				FinishErr = 1.0,
				Coe = -1
			});
			Devices.Add(new DeviceCondition
			{
				Id = 8,
				Device = Lang.Txt("Tune.D2"),
				Force = true,
				MaxValue = -60.0,
				MinValue = -10.0,
				DefaultValue = -25.0,
				MinLimit = -10.0,
				MaxLimit = -100.0,
				Step = 5.0,
				ReadErr = 0.5,
				FinishErr = 1.0,
				Coe = -1
			});
			Devices.Add(new DeviceCondition
			{
				Id = 12,
				Device = "DA",
				Force = true,
				MaxValue = -100.0,
				MinValue = -1.0,
				DefaultValue = -60.0,
				MinLimit = -1.0,
				MaxLimit = -100.0,
				Step = 5.0,
				ReadErr = 0.5,
				FinishErr = 5.0,
				Coe = -1
			});
			Devices.Add(new DeviceCondition
			{
				Id = 10,
				Device = Lang.Txt("FormConfig.Columns.Hexapole.Text"),
				Force = true,
				MaxValue = -30.0,
				MinValue = -20.0,
				DefaultValue = -25.0,
				MinLimit = -1.0,
				MaxLimit = -30.0,
				Step = 0.5,
				ReadErr = 0.5,
				FinishErr = 1.0,
				Coe = -1
			});
			Devices.Add(new DeviceCondition
			{
				Id = 18,
				Device = Lang.Txt("FormConfig.Columns.QuadPole.Text"),
				Force = true,
				MaxValue = -15.0,
				MinValue = -1.0,
				DefaultValue = -10.0,
				MinLimit = -1.0,
				MaxLimit = -15.0,
				Step = 0.5,
				ReadErr = 0.5,
				FinishErr = 1.0,
				Coe = -1
			});
			Devices.Add(new DeviceCondition
			{
				Id = 19,
				Device = Lang.Txt("FormQuad.PreBias.Text"),
				Force = true,
				MaxValue = -15.0,
				MinValue = -1.0,
				DefaultValue = -10.0,
				MinLimit = -1.0,
				MaxLimit = -15.0,
				Step = 0.5,
				ReadErr = 0.5,
				FinishErr = 1.0,
				Coe = -1
			});
			Devices.Add(new DeviceCondition
			{
				Id = 20,
				Device = Lang.Txt("FormRF.SixPoleCoefficient.Text"),
				Force = true,
				MaxValue = 10.0,
				MinValue = 0.0,
				DefaultValue = 7.0,
				Step = 0.5,
				MinLimit = 0.0,
				MaxLimit = 10.0,
				ReadErr = 0.5,
				FinishErr = 1.0,
				Coe = 1
			});
			Devices.Add(new DeviceCondition
			{
				Id = 14,
				Device = Lang.Txt("FormIonSource.CoolGas.Text"),
				Force = true,
				MaxValue = 16.0,
				MinValue = 10.0,
				DefaultValue = 13.0,
				Step = 0.5,
				ReadErr = 0.1,
				FinishErr = 0.1,
				Coe = 1
			});
			Devices.Add(new DeviceCondition
			{
				Id = 15,
				Device = Lang.Txt("FormIonSource.Nebulizer.Text"),
				Force = true,
				MaxValue = 1.6,
				MinValue = 0.5,
				DefaultValue = 0.8,
				Step = 0.1,
				ReadErr = 0.1,
				FinishErr = 0.005,
				Coe = 1
			});
			Devices.Add(new DeviceCondition
			{
				Id = 16,
				Device = Lang.Txt("Tune.CollisionGas"),
				Force = false,
				MaxValue = 3.0,
				MinValue = 0.0,
				DefaultValue = 1.5,
				Step = 0.1,
				ReadErr = 0.1,
				FinishErr = 0.05,
				Coe = 1
			});
			Devices.Add(new DeviceCondition
			{
				Id = 21,
				Device = Lang.Txt("Tune.KEDVoltage"),
				Force = false,
				MaxValue = 6.0,
				MinValue = 2.0,
				DefaultValue = 3.0,
				Step = 1.0,
				MinLimit = 0.0,
				MaxLimit = 10.0,
				ReadErr = 0.1,
				FinishErr = 0.05,
				Coe = 1
			});
		}
	}

	public bool CheckPosition(double value, DeviceCondition dev)
	{
		switch (dev.Id)
		{
		case 0:
			if (Math.Abs(PlatManager.plat.ReadX / 100.0 - value) <= value * dev.ReadErr)
			{
				return true;
			}
			break;
		case 1:
			if (Math.Abs(PlatManager.plat.ReadZ / 100.0 - value) <= value * dev.ReadErr)
			{
				return true;
			}
			break;
		case 2:
			if (Math.Abs(PlatManager.plat.ReadY / 100.0 - value) <= value * dev.ReadErr)
			{
				return true;
			}
			break;
		case 3:
			if (Math.Abs(LensManager.x2lens.ReadEx - value) <= Math.Abs(value) * 0.5)
			{
				return true;
			}
			break;
		case 4:
			if (Math.Abs(LensManager.x2lens.ReadL1 - value) <= Math.Abs(value) * dev.ReadErr)
			{
				return true;
			}
			break;
		case 5:
			if (Math.Abs(LensManager.x2lens.ReadL2 - value) <= Math.Abs(value) * dev.ReadErr)
			{
				return true;
			}
			break;
		case 6:
			if (Math.Abs(LensManager.x2lens.ReadF - value) <= dev.ReadErr)
			{
				return true;
			}
			break;
		case 7:
			if (Math.Abs(LensManager.x2lens.ReadD1 - value) <= Math.Abs(value) * dev.ReadErr)
			{
				return true;
			}
			break;
		case 8:
			if (Math.Abs(LensManager.x2lens.ReadD2 - value) <= Math.Abs(value) * dev.ReadErr)
			{
				return true;
			}
			break;
		case 9:
			if (Math.Abs(LensManager.x2lens.ReadQE - value) <= Math.Abs(value) * dev.ReadErr)
			{
				return true;
			}
			break;
		case 10:
			if (Math.Abs(LensManager.x2lens.ReadPole - value) <= Math.Abs(value) * dev.ReadErr)
			{
				return true;
			}
			break;
		case 11:
			if (Math.Abs(LensManager.x2lens.ReadL3 - value) <= Math.Abs(value) * dev.ReadErr)
			{
				return true;
			}
			break;
		case 12:
			if (Math.Abs(LensManager.x2lens.ReadDA - value) <= Math.Abs(value) * dev.ReadErr)
			{
				return true;
			}
			break;
		case 13:
			if (Math.Abs(PlasmaManager.plasma.ReadNebuliser - value) <= value * dev.ReadErr)
			{
				return true;
			}
			break;
		case 14:
			if (Math.Abs(PlasmaManager.plasma.ReadCool - value) <= value * dev.ReadErr)
			{
				return true;
			}
			break;
		case 15:
			if (Math.Abs(PlasmaManager.plasma.ReadAuxiliary - value) <= value * dev.ReadErr)
			{
				return true;
			}
			break;
		case 16:
			if (Math.Abs(PlasmaManager.plasma.ReadCollision - value) <= value * dev.ReadErr)
			{
				return true;
			}
			break;
		case 17:
			if (Math.Abs(PlasmaManager.plasma.ReadForward - value) <= value * dev.ReadErr)
			{
				return true;
			}
			break;
		case 18:
		case 19:
		case 20:
			Thread.Sleep(2000);
			return true;
		}
		return false;
	}

	public double ReadPosition(DeviceCondition dev)
	{
		double xx = -1.0;
		switch (dev.Id)
		{
		case 0:
			xx = PlatManager.plat.ReadX / 100.0;
			break;
		case 1:
			xx = PlatManager.plat.ReadZ / 100.0;
			break;
		case 2:
			xx = PlatManager.plat.ReadY / 100.0;
			break;
		case 3:
			xx = LensManager.x2lens.ReadEx;
			break;
		case 4:
			xx = LensManager.x2lens.ReadL1;
			break;
		case 5:
			xx = LensManager.x2lens.ReadL2;
			break;
		case 6:
			xx = LensManager.x2lens.ReadF;
			break;
		case 7:
			xx = LensManager.x2lens.ReadD1;
			break;
		case 8:
			xx = LensManager.x2lens.ReadD2;
			break;
		case 9:
			xx = LensManager.x2lens.ReadQE;
			break;
		case 10:
			xx = LensManager.x2lens.ReadPole;
			break;
		case 11:
			xx = LensManager.x2lens.ReadL3;
			break;
		case 12:
			xx = LensManager.x2lens.ReadDA;
			break;
		case 13:
			xx = PlasmaManager.plasma.ReadNebuliser;
			break;
		case 14:
			xx = PlasmaManager.plasma.ReadCool;
			break;
		case 15:
			xx = PlasmaManager.plasma.ReadAuxiliary;
			break;
		case 16:
			xx = PlasmaManager.plasma.ReadCollision;
			break;
		case 17:
			xx = PlasmaManager.plasma.ReadForward;
			break;
		case 18:
			xx = RFManager.rfs.quadPole;
			break;
		case 19:
			xx = RFManager.rfs.prePole;
			break;
		}
		return xx;
	}

	public void UpdateTuneDevices()
	{
		List<DeviceCondition> selectDevices = Devices.Where((DeviceCondition device) => device.Selected).ToList();
		foreach (TuneStage stage2 in Stages)
		{
			stage2.Devices.RemoveAll((DeviceCondition stageDev) => !selectDevices.Exists((DeviceCondition dev) => dev.Id == stageDev.Id));
		}
		foreach (TuneStage stage in Stages)
		{
			foreach (DeviceCondition dev2 in selectDevices)
			{
				if (!stage.Devices.Exists((DeviceCondition stageDev) => stageDev.Id == dev2.Id))
				{
					stage.Devices.Add(dev2.Clone());
				}
				else
				{
					stage.UpdateDevice(dev2);
				}
			}
		}
	}

	public void UpdateTuneParams()
	{
		Params.Clear();
		foreach (TuneIsotope isotope in Isotopes)
		{
			Params.Add(new ParamConditon
			{
				Id = 0,
				Isotope = isotope,
				Ratio = null,
				Symbol = isotope.Symbol,
				Type = 0,
				Limit = 0.0
			});
		}
		foreach (TuneRatio ratio in Ratios)
		{
			Params.Add(new ParamConditon
			{
				Id = 0,
				Isotope = null,
				Ratio = ratio,
				Symbol = ratio.Numerator.Symbol + "/" + ratio.Denominator.Symbol,
				Type = 0,
				Limit = 0.0
			});
		}
		foreach (TuneStage stage2 in Stages)
		{
			stage2.Params.RemoveAll((ParamConditon stagePara) => !Params.Exists((ParamConditon para) => para.Symbol == stagePara.Symbol));
		}
		foreach (TuneStage stage in Stages)
		{
			foreach (ParamConditon para2 in Params)
			{
				if (!stage.Params.Exists((ParamConditon stagePara) => stagePara.Symbol == para2.Symbol))
				{
					stage.Params.Add(para2.Clone());
				}
			}
		}
	}

	public void UpdateTuneStage(TuneStage stage)
	{
		foreach (DeviceCondition device in Devices.Where((DeviceCondition dev) => dev.Selected))
		{
			stage.Devices.Add(device.Clone());
		}
		foreach (ParamConditon para in Params)
		{
			stage.Params.Add(para.Clone());
		}
	}

	public bool SaveConfig()
	{
		string path = Application.StartupPath + "\\Autotune\\" + Name + ".xml";
		XMLFile.Save(path, this);
		return true;
	}

	public bool DeleteConfig(string name)
	{
		string path = Application.StartupPath + "\\Autotune\\" + name + ".xml";
		if (File.Exists(path))
		{
			File.Delete(path);
		}
		return true;
	}

	public static string[] LoadAllConfigs()
	{
		string dir = Application.StartupPath + "\\Autotune";
		if (!Directory.Exists(dir))
		{
			Directory.CreateDirectory(dir);
		}
		return Directory.GetFiles(dir, "*.xml", SearchOption.TopDirectoryOnly);
	}

	public static AutoTuneExperiment LoadConfig(string name)
	{
		AutoTuneExperiment experiment = null;
		string path = Application.StartupPath + "\\Autotune\\" + name + ".xml";
		XMLFile.Open(path, ref experiment);
		return experiment;
	}

	public void Skip(bool bSkip)
	{
		bSkipped = bSkip;
	}

	public void StartTune(string name = "")
	{
		Detector.finishReceive += Detector_finishReceive;
		isTuning = true;
		if (Name.Contains(Lang.Txt("Tune.KEDMode")))
		{
			threadTune = new Thread(TuneKED);
		}
		else if (Name == Lang.Txt("ADDTune.Tune.StandardMode"))
		{
			threadTune = new Thread(ThreadTuneTest);
		}
		else
		{
			threadTune = new Thread(ThreadTune);
		}
		threadTune.Start();
	}

	public void StartTuneEx()
	{
		Detector.finishReceive += Detector_finishReceive;
		isTuning = true;
		threadTune = new Thread(ThreadTuneTest);
		threadTune.Start();
	}

	private bool TuneDeviceRelated(TuneStage stage, List<DeviceCondition> stageDevices)
	{
		if (stageDevices.Count == 1)
		{
			double bestValue = 0.0;
			if (!MaxMinTune2(stage, stageDevices[0], related: true, out bestValue))
			{
				return false;
			}
			ParamConditon tunePara2 = stage.Params.Where((ParamConditon para) => para.Type == 1 || para.Type == 2).First();
			if (tunePara2.Type == 1)
			{
				if (BestResult == -1.0)
				{
					BestResult = tunePara2.BestResult;
				}
				else
				{
					if (!(tunePara2.BestResult - BestResult > 0.0))
					{
						if (stage.Devices.Where((DeviceCondition r) => r.Used).Count() != 2)
						{
							stage.Finished = true;
						}
						return true;
					}
					BestResult = tunePara2.BestResult;
				}
			}
			else if (BestResult == -1.0)
			{
				BestResult = tunePara2.BestResult;
			}
			else if (BestResult - tunePara2.BestResult > 0.0)
			{
				BestResult = tunePara2.BestResult;
			}
			else if (BestResult > 1500.0)
			{
				if (stage.Devices.Where((DeviceCondition r) => r.Used).Count() != 2)
				{
					stage.Finished = true;
				}
				return true;
			}
			if (BestResult > 50.0)
			{
				stageDevices[0].MinValue = stageDevices[0].BestValue - stageDevices[0].Step * 2.0 * (double)stageDevices[0].Coe;
				if (Math.Abs(stageDevices[0].MinValue) < Math.Abs(stageDevices[0].MinLimit))
				{
					stageDevices[0].MinValue = stageDevices[0].MinLimit;
				}
				stageDevices[0].MaxValue = stageDevices[0].BestValue + stageDevices[0].Step * 2.0 * (double)stageDevices[0].Coe;
				if (Math.Abs(stageDevices[0].MaxValue) > Math.Abs(stageDevices[0].MaxLimit))
				{
					stageDevices[0].MaxValue = stageDevices[0].MaxLimit;
				}
			}
		}
		else
		{
			DeviceCondition device = stageDevices[0];
			double minvalue = 0.0;
			double maxvalue = 0.0;
			if (stageDevices.Count > 1)
			{
				minvalue = stageDevices[stageDevices.Count - 1].MinValue;
				maxvalue = stageDevices[stageDevices.Count - 1].MaxValue;
				ParamConditon tunePara = stage.Params.Where((ParamConditon para) => para.Type == 1 || para.Type == 2).First();
				tunePara.BestResult = 0.0;
				BestResult = -1.0;
			}
			for (double deviceSets = device.MinValue * (double)device.Coe; deviceSets <= device.MaxValue * (double)device.Coe; deviceSets += device.Step)
			{
				TuneMsg($"set {device.Device} to {deviceSets * (double)device.Coe}");
				SetDeviceValue(device.Id, deviceSets * (double)device.Coe);
				if (!TuneDeviceRelated(stage, stageDevices.GetRange(1, stageDevices.Count - 1)))
				{
					return false;
				}
				if (!bSkipped && !stage.Finished)
				{
					continue;
				}
				if (stage.Devices.Count >= 3)
				{
					stageDevices[stageDevices.Count - 2].MaxValue = deviceSets * (double)device.Coe + device.Step * (double)device.Coe * 3.0;
					if (Math.Abs(stageDevices[stageDevices.Count - 2].MaxValue) > Math.Abs(stageDevices[stageDevices.Count - 2].MaxLimit))
					{
						stageDevices[stageDevices.Count - 2].MaxValue = stageDevices[stageDevices.Count - 2].MaxLimit;
					}
					stageDevices[stageDevices.Count - 2].MinValue = deviceSets * (double)device.Coe - device.Step * (double)device.Coe;
					if (stageDevices[stageDevices.Count - 2].MinValue > stageDevices[stageDevices.Count - 2].MinLimit)
					{
						stageDevices[stageDevices.Count - 2].MinValue = stageDevices[stageDevices.Count - 2].MinLimit;
					}
				}
				stage.Finished = false;
				break;
			}
		}
		return true;
	}

	private bool TuneDevice1(TuneStage stage, DeviceCondition device, double value)
	{
		if (!TuneDevice(stage, device, value))
		{
			return false;
		}
		ParamConditon tunePara = stage.Params.Where((ParamConditon para) => para.Type == 1 || para.Type == 2).First();
		List<double> result = new List<double>();
		List<DeviceCondition> devs = stage.Devices.Where((DeviceCondition r) => r.Used).ToList();
		for (int i = 0; i < devs.Count(); i++)
		{
			result.Add(devs[i].DeviceSets);
		}
		result.Add(tunePara.Result);
		StageDeviceResult.Add(result);
		return true;
	}

	private bool TuneDeviceForBestResult(TuneStage stage, List<DeviceCondition> stageDevices)
	{
		if (stageDevices.Count == 1)
		{
			ParamConditon tunePara2 = stage.Params.Where((ParamConditon para) => para.Type == 1 || para.Type == 2).First();
			double step2 = stageDevices[0].Step;
			if (stageDevices[0].FirstComp)
			{
				double val4 = stageDevices[0].DefaultValue;
				double val6 = stageDevices[0].DefaultValue + step2;
				if (!TuneDevice1(stage, stageDevices[0], val4))
				{
					return false;
				}
				double result2 = tunePara2.Result;
				if (stage.Params.Find((ParamConditon r) => r.Type == 1 || r.Type == 2).Pass)
				{
					TuneSucceed = true;
					return true;
				}
				if (!TuneDevice1(stage, stageDevices[0], val6))
				{
					return false;
				}
				double result4 = tunePara2.Result;
				if (stage.Params.Find((ParamConditon r) => r.Type == 1 || r.Type == 2).Pass)
				{
					TuneSucceed = true;
					return true;
				}
				if (result2 > result4)
				{
					step2 = 0.0 - step2;
					stageDevices[0].BestValue = val4;
					stageDevices[0].BestResult = result2;
				}
				else
				{
					stageDevices[0].BestValue = val6;
					stageDevices[0].BestResult = result4;
				}
				stageDevices[0].FirstComp = false;
			}
			double val2 = stageDevices[0].BestValue;
			if (!TuneDevice1(stage, stageDevices[0], val2))
			{
				return false;
			}
			stageDevices[0].BestValue = val2;
			stageDevices[0].BestResult = tunePara2.Result;
			for (val2 += step2; val2 * (double)stageDevices[0].Coe > stageDevices[0].MinValue * (double)stageDevices[0].Coe && val2 < stageDevices[0].MaxValue * (double)stageDevices[0].Coe; val2 += step2)
			{
				if (!TuneDevice1(stage, stageDevices[0], val2))
				{
					return false;
				}
				if (stage.Params.Find((ParamConditon r) => r.Type == 1 || r.Type == 2).Pass)
				{
					TuneSucceed = true;
					return true;
				}
				if (tunePara2.Result < stageDevices[0].BestResult)
				{
					stageDevices[0].DefaultValue = stageDevices[0].BestValue;
					break;
				}
				stageDevices[0].BestValue = val2;
				stageDevices[0].BestResult = tunePara2.Result;
			}
			return true;
		}
		DeviceCondition device = stageDevices[0];
		ParamConditon tunePara = stage.Params.Where((ParamConditon para) => para.Type == 1 || para.Type == 2).First();
		double step = device.Step;
		if (device.FirstComp)
		{
			double val3 = device.DefaultValue;
			double val5 = device.DefaultValue + device.Step;
			TuneMsg($"set {device.Device} to {val3}");
			SetDeviceValue(device.Id, val3);
			device.DeviceSets = val3;
			if (!TuneDeviceForBestResult(stage, stageDevices.GetRange(1, stageDevices.Count - 1)))
			{
				return false;
			}
			if (TuneSucceed)
			{
				return true;
			}
			double result1 = stageDevices[1].BestResult;
			TuneMsg($"set {device.Device} to {val5}");
			SetDeviceValue(device.Id, val5);
			device.DeviceSets = val5;
			if (!TuneDeviceForBestResult(stage, stageDevices.GetRange(1, stageDevices.Count - 1)))
			{
				return false;
			}
			if (TuneSucceed)
			{
				return true;
			}
			double result3 = stageDevices[1].BestResult;
			if (result1 > result3)
			{
				step = 0.0 - step;
				device.BestValue = val3;
				device.BestResult = result1;
			}
			else
			{
				device.BestValue = val5;
				device.BestResult = result3;
			}
			device.FirstComp = false;
		}
		if (step < 0.0)
		{
			stageDevices[1].Step = 0.0 - Math.Abs(stageDevices[1].Step);
		}
		else
		{
			stageDevices[1].Step = Math.Abs(stageDevices[1].Step);
		}
		double val = -1.0;
		if (device.Id != 3 || device.Id != 6)
		{
			val = device.BestValue;
			TuneMsg($"set {device.Device} to {val}");
			SetDeviceValue(device.Id, val);
			device.DeviceSets = val;
			if (!TuneDeviceForBestResult(stage, stageDevices.GetRange(1, stageDevices.Count - 1)))
			{
				return false;
			}
			if (TuneSucceed)
			{
				return true;
			}
			device.BestValue = val;
			device.BestResult = stageDevices[1].BestResult;
			val = device.BestValue + step;
		}
		else
		{
			int index = -1;
			double comp = -1.0;
			for (int i = 0; i < StageDeviceResult.Count; i++)
			{
				if (StageDeviceResult[i].Last() > comp)
				{
					comp = StageDeviceResult[i].Last();
					index = i;
				}
			}
			List<DeviceCondition> devices = stage.Devices.FindAll((DeviceCondition r) => r.Used);
			for (int j = 0; j < devices.Count; j++)
			{
				devices[j].BestValue = StageDeviceResult[index][j];
			}
			val = device.BestValue + step;
		}
		while (val * (double)device.Coe > device.MinValue * (double)device.Coe && val * (double)device.Coe < device.MaxValue * (double)device.Coe)
		{
			TuneMsg($"set {device.Device} to {val}");
			SetDeviceValue(device.Id, val);
			device.DeviceSets = val;
			if (!TuneDeviceForBestResult(stage, stageDevices.GetRange(1, stageDevices.Count - 1)))
			{
				return false;
			}
			if (TuneSucceed)
			{
				return true;
			}
			if (tunePara.Type == 1)
			{
				if (!(stageDevices[1].BestResult - device.BestResult > 0.0))
				{
					device.Finished = true;
					if (stage.Devices.FindIndex((DeviceCondition r) => r.Id == device.Id) == 0 && stage.Devices.Count != 2)
					{
						stage.Finished = true;
					}
					stageDevices[1].Step = Math.Abs(stageDevices[1].Step);
					return true;
				}
				device.BestResult = stageDevices[1].BestResult;
				device.BestValue = val;
			}
			val = device.BestValue + step;
		}
		return true;
	}

	private bool TuneDeviceRelatedForMany(TuneStage stage, List<DeviceCondition> stageDevices)
	{
		if (stageDevices.Count == 1)
		{
			double bestValue = 0.0;
			if (!MaxMinTune2(stage, stageDevices[0], related: true, out bestValue))
			{
				return false;
			}
			ParamConditon tunePara = stage.Params.Where((ParamConditon para) => para.Type == 1 || para.Type == 2).First();
			if (tunePara.BestResult > 50.0)
			{
				stageDevices[0].MinValue = stageDevices[0].BestValue - stageDevices[0].Step * 2.0 * (double)stageDevices[0].Coe;
				if (Math.Abs(stageDevices[0].MinValue) < Math.Abs(stageDevices[0].MinLimit))
				{
					stageDevices[0].MinValue = stageDevices[0].MinLimit;
				}
				stageDevices[0].MaxValue = stageDevices[0].BestValue + stageDevices[0].Step * 2.0 * (double)stageDevices[0].Coe;
				if (Math.Abs(stageDevices[0].MaxValue) > Math.Abs(stageDevices[0].MaxLimit))
				{
					stageDevices[0].MaxValue = stageDevices[0].MaxLimit;
				}
			}
			return true;
		}
		DeviceCondition device = stageDevices[0];
		for (double deviceSets = device.MinValue * (double)device.Coe; deviceSets <= device.MaxValue * (double)device.Coe; deviceSets += device.Step)
		{
			stageDevices[1].BestResult = -1.0;
			TuneMsg($"set {device.Device} to {deviceSets * (double)device.Coe}");
			SetDeviceValue(device.Id, deviceSets * (double)device.Coe);
			if (!TuneDeviceRelatedForMany(stage, stageDevices.GetRange(1, stageDevices.Count - 1)))
			{
				return false;
			}
			ParamConditon tunePara2 = stage.Params.Where((ParamConditon para) => para.Type == 1 || para.Type == 2).First();
			if (tunePara2.Type == 1)
			{
				if (device.BestResult == -1.0)
				{
					device.BestResult = stageDevices[1].BestResult;
				}
				else if (stageDevices[1].BestResult - device.BestResult > 0.0)
				{
					device.BestResult = stageDevices[1].BestResult;
				}
				else
				{
					device.Finished = true;
					if (stage.Devices.FindIndex((DeviceCondition r) => r.Id == device.Id) == 0 && stage.Devices.Count != 2)
					{
						stage.Finished = true;
						return true;
					}
					device.BestValue = deviceSets;
				}
			}
			else if (device.BestResult == -1.0)
			{
				device.BestResult = stageDevices[1].BestResult;
			}
			else if (device.BestResult - stageDevices[1].BestResult > 0.0)
			{
				device.BestResult = stageDevices[1].BestResult;
			}
			else if (device.BestResult > 1500.0)
			{
				device.Finished = true;
				if (stage.Devices.FindIndex((DeviceCondition r) => r.Id == device.Id) == 0 && stage.Devices.Count() != 2)
				{
					stage.Finished = true;
					return true;
				}
				device.BestValue = deviceSets;
			}
			if (!bSkipped && !device.Finished)
			{
				continue;
			}
			if (stage.Devices.Count >= 3)
			{
				device.MaxValue = deviceSets * (double)device.Coe + device.Step * (double)device.Coe * 2.0;
				if (Math.Abs(device.MaxValue) > Math.Abs(device.MaxLimit))
				{
					device.MaxValue = device.MaxLimit;
				}
				device.MinValue = deviceSets * (double)device.Coe - device.Step * (double)device.Coe * 2.0;
				if (device.MinValue > device.MinLimit)
				{
					device.MinValue = device.MinLimit;
				}
				device.Finished = false;
				break;
			}
			if (bSkipped)
			{
				break;
			}
		}
		return true;
	}

	private void Detector_errorReceive(object sender, ErrorMsgEventArgs e)
	{
		LensManager.x2lens.Etp = 0.0;
		LensManager.Instance.SetEtp();
		StopTune();
		MessageBox.Show(Lang.Txt("Tune.Mesg1") + e.X + Lang.Txt("Tune.Mesg2"), Lang.Txt("Tune.Mesg3"));
	}

	public void StopTune()
	{
		isTuning = false;
		Detector.finishReceive -= Detector_finishReceive;
		if (threadTune != null && threadTune.IsAlive)
		{
			threadTune.Abort();
		}
		Detector.Instance.Stop();
		Detector.Instance.ExperimentState = -1;
	}

	private void Detector_finishReceive(object sender, EventArgs e)
	{
		scanEvent.Set();
	}

	public void SetDefaultValue()
	{
		foreach (TuneStage stage in Stages.Where((TuneStage s) => s.Selected))
		{
			foreach (DeviceCondition dev in stage.Devices.Where((DeviceCondition r) => r.Used))
			{
				switch (dev.Id)
				{
				case 0:
					dev.DefaultValue = PlatManager.plat.ReadX / 100.0;
					break;
				case 1:
					dev.DefaultValue = PlatManager.plat.ReadZ / 100.0;
					break;
				case 2:
					dev.DefaultValue = PlatManager.plat.ReadY / 100.0;
					break;
				case 3:
					dev.DefaultValue = LensManager.x2lens.ReadEx;
					break;
				case 4:
					dev.DefaultValue = LensManager.x2lens.ReadL1;
					break;
				case 5:
					dev.DefaultValue = LensManager.x2lens.ReadL2;
					break;
				case 6:
					dev.DefaultValue = LensManager.x2lens.ReadF;
					break;
				case 7:
					dev.DefaultValue = LensManager.x2lens.ReadD1;
					break;
				case 8:
					dev.DefaultValue = LensManager.x2lens.ReadD2;
					break;
				case 9:
					dev.DefaultValue = LensManager.x2lens.ReadQE;
					break;
				case 10:
					dev.DefaultValue = LensManager.x2lens.ReadPole;
					break;
				case 11:
					dev.DefaultValue = LensManager.x2lens.ReadL3;
					break;
				case 12:
					dev.DefaultValue = LensManager.x2lens.ReadDA;
					break;
				case 13:
					dev.DefaultValue = PlasmaManager.plasma.ReadNebuliser;
					break;
				case 14:
					dev.DefaultValue = PlasmaManager.plasma.ReadCool;
					break;
				case 15:
					dev.DefaultValue = PlasmaManager.plasma.ReadAuxiliary;
					break;
				case 16:
					dev.DefaultValue = PlasmaManager.plasma.ReadCollision;
					break;
				case 17:
					dev.DefaultValue = PlasmaManager.plasma.ReadForward;
					break;
				case 21:
					dev.DefaultValue = RFManager.rfs.ReadQuadPole + LensManager.x2lens.ReadPole;
					break;
				case 19:
					dev.DefaultValue = RFManager.rfs.prePole;
					break;
				case 18:
					dev.DefaultValue = RFManager.rfs.quadPole;
					break;
				}
			}
		}
	}

	public void LoadConfigration(string name)
	{
		X2Lens lens = DataBase.Instance.GetX2Lens(name);
		if (lens != null)
		{
			LensManager.x2lens = lens;
		}
		else
		{
			Log.InsertLog("Load Configration", "Load lens params error.", "", (Severity)3);
		}
		PlasmaPara plasma = DataBase.Instance.GetPlasma(name);
		if (plasma != null)
		{
			PlasmaManager.plasma = plasma;
		}
		else
		{
			Log.InsertLog("Load Configration", "Load plasma params error.", "", (Severity)3);
		}
		RFS rfs = DataBase.Instance.GetRFS(name);
		if (rfs != null)
		{
			RFManager.rfs = rfs;
		}
		else
		{
			Log.InsertLog("Load Configration", "Load rf params error.", "", (Severity)3);
		}
		InstrumentInjector injector = DataBase.Instance.GetInjector(name);
		if (injector != null)
		{
			PlatManager.Instrumentinjector.Perist = injector.Perist;
		}
		else
		{
			PlatManager.Instrumentinjector.Perist = 350;
		}
		Platform plat = DataBase.Instance.GetPlatform(name);
		if (plat != null)
		{
			PlatManager.plat = plat.Clone();
		}
		else
		{
			Log.InsertLog("Load Configration", "Load platform params error.", "", (Severity)3);
		}
	}

	public void SetConfig()
	{
		List<InstrumentConfig> instrumentConfigs = DataBase.Instance.GetAllInstrumentConfigs().ToList();
		if (instrumentConfigs != null && instrumentConfigs.Count != 0)
		{
			InstrumentConfig instrumentConfig = instrumentConfigs.Find((InstrumentConfig r) => r.Description == Lang.Txt("ADDTune.Tune.StandardMode"));
			if (instrumentConfig != null)
			{
				LoadConfigration(instrumentConfig.Time);
			}
			LensManager.Instance.X2_SetAll();
			Plasma.Instance.OpenCoolGas();
			Plasma.Instance.OpenNebulizerGas();
			Plasma.Instance.SetPower();
			if (Collision.Instance.CRCType == 1)
			{
				Plasma.Instance.OpenCollision();
			}
			else
			{
				Plasma.Instance.OpenCollision();
				Plasma.Instance.OpenCollision2();
			}
			Plasma.Instance.OpenAppendixGas();
			Detector.Instance.msDetectorRF.SetSuspend(false);
			Detector.Instance.msDetectorRF.SetStable();
			if (Detector.detectorConfig.IsNewDetector)
			{
				Detector.Instance.msDetectorRF.SetQuadPoleNew();
				Detector.Instance.msDetectorRF.SetPrePoleNew();
				Detector.Instance.msDetectorRF.SetHVNNew();
				Thread.Sleep(1);
				Detector.Instance.msDetectorRF.SetHVPNew();
				Thread.Sleep(1);
				Detector.Instance.msDetectorRF.SetGateNew();
			}
			else
			{
				Detector.Instance.msDetectorRF.SetQuadPole();
				Detector.Instance.msDetectorRF.SetPrePole();
				Detector.Instance.msDetectorRF.SetHVN();
				Thread.Sleep(1);
				Detector.Instance.msDetectorRF.SetHVP();
				Thread.Sleep(1);
				Detector.Instance.msDetectorRF.SetGate();
			}
			Plasma.Instance.SetPlatform();
			Plasma.Instance.SetPeristaltic(PlatManager.Instrumentinjector.Perist);
		}
	}

	private void ThreadTuneTest()
	{
		foreach (TuneStage stage in Stages)
		{
			TuneMsg($"Stage:{stage.StageName}");
			TuneMsg($"Starting {stage.StageName}");
			InitScanDatas(stage);
			for (int iterationIdx = 0; iterationIdx < stage.Iterations; iterationIdx++)
			{
				TuneMsg($"Iteration {iterationIdx}");
				if (!stage.Selected)
				{
					break;
				}
				if (stage.Devices.Where((DeviceCondition r) => r.Used).Count() <= 0 || stage.Params.Where((ParamConditon r) => r.Type == 1 || r.Type == 2).Count() <= 0)
				{
					continue;
				}
				StageDeviceResult.Clear();
				stage.Finished = false;
				ParamConditon tunePara = stage.Params.Where((ParamConditon para) => para.Type == 1 || para.Type == 2).First();
				tunePara.BestResult = 0.0;
				if (stage.Devices.Find((DeviceCondition r) => (r.Id == 12 || r.Id == 9) && r.Used) != null)
				{
					if (!TuneDeviceRelatedForMany(stage, stage.Devices.Where((DeviceCondition r) => r.Used).ToList()))
					{
						TuneMsg("Scan error.");
						TuneFinish(error: true);
						return;
					}
				}
				else
				{
					foreach (DeviceCondition device in stage.Devices)
					{
						device.FirstComp = true;
					}
					if (!TuneDeviceForBestResult(stage, stage.Devices.Where((DeviceCondition r) => r.Used).ToList()))
					{
						TuneMsg("Scan error.");
						TuneFinish(error: true);
						return;
					}
				}
				if (StageDeviceResult.Count > 0)
				{
					double max = 0.0;
					int maxindex = -1;
					for (int k = 0; k < StageDeviceResult.Count; k++)
					{
						if (tunePara.Type == 1)
						{
							if (StageDeviceResult[k].Last() >= max)
							{
								max = StageDeviceResult[k].Last();
								maxindex = k;
							}
						}
						else if (StageDeviceResult[k].Last() <= max)
						{
							max = StageDeviceResult[k].Last();
							maxindex = k;
						}
					}
					List<DeviceCondition> devs = stage.Devices.Where((DeviceCondition r) => r.Used).ToList();
					if (maxindex != -1)
					{
						string msg = Lang.Txt("Tune.OptimalValue");
						for (int i = 0; i < devs.Count; i++)
						{
							devs[i].BestValue = StageDeviceResult[maxindex][i];
							SetDeviceValue(devs[i].Id, devs[i].BestValue);
							msg = msg + devs[i].Device + ":" + devs[i].BestValue.ToString("F2") + "  ";
						}
						TuneMsg(msg);
						tunePara.BestResult = max;
						msg = "";
						msg = msg + "BestResult:" + tunePara.BestResult.ToString("F2");
					}
					else
					{
						for (int j = 0; j < devs.Count; j++)
						{
							devs[j].BestValue = devs[j].DefaultValue;
							SetDeviceValue(devs[j].Id, devs[j].DefaultValue);
						}
					}
				}
				if (TuneSucceed)
				{
					break;
				}
			}
			if (TuneSucceed)
			{
				break;
			}
		}
		TuneFinish(error: false);
	}

	private void ThreadTune()
	{
		foreach (TuneStage stage in Stages)
		{
			TuneMsg($"Stage:{stage.StageName}");
			TuneMsg($"Starting {stage.StageName}");
			InitScanDatas(stage);
			for (int iterationIdx = 0; iterationIdx < stage.Iterations; iterationIdx++)
			{
				TuneMsg($"Iteration {iterationIdx}");
				if (!stage.Selected)
				{
					break;
				}
				if (stage.Devices.Where((DeviceCondition r) => r.Used && r.Related).Count() > 0 && stage.Params.Where((ParamConditon r) => r.Type == 1 || r.Type == 2).Count() > 0)
				{
					StageDeviceResult.Clear();
					stage.Finished = false;
					ParamConditon tunePara = stage.Params.Where((ParamConditon para) => para.Type == 1 || para.Type == 2).First();
					tunePara.BestResult = 0.0;
					if (!TuneDeviceRelatedForMany(stage, stage.Devices.Where((DeviceCondition r) => r.Used && r.Related).ToList()))
					{
						TuneMsg("Scan error.");
						TuneFinish(error: true);
						return;
					}
					if (StageDeviceResult.Count > 0)
					{
						double max = 0.0;
						int maxindex = -1;
						for (int k = 0; k < StageDeviceResult.Count; k++)
						{
							if (tunePara.Type == 1)
							{
								if (StageDeviceResult[k].Last() >= max)
								{
									max = StageDeviceResult[k].Last();
									maxindex = k;
								}
							}
							else if (StageDeviceResult[k].Last() <= max)
							{
								max = StageDeviceResult[k].Last();
								maxindex = k;
							}
						}
						List<DeviceCondition> devs = stage.Devices.Where((DeviceCondition r) => r.Used).ToList();
						if (maxindex != -1)
						{
							string msg3 = Lang.Txt("Tune.OptimalValue");
							for (int i = 0; i < devs.Count; i++)
							{
								devs[i].BestValue = StageDeviceResult[maxindex][i];
								SetDeviceValue(devs[i].Id, devs[i].BestValue);
								msg3 = msg3 + devs[i].Device + ":" + devs[i].BestValue.ToString("F2") + "  ";
							}
							TuneMsg(msg3);
							tunePara.BestResult = max;
							msg3 = "";
							msg3 = msg3 + "BestResult:" + tunePara.BestResult.ToString("F2");
						}
						else
						{
							for (int j = 0; j < devs.Count; j++)
							{
								devs[j].BestValue = devs[j].DefaultValue;
								SetDeviceValue(devs[j].Id, devs[j].DefaultValue);
							}
						}
					}
				}
				foreach (DeviceCondition device in stage.Devices.Where((DeviceCondition dev) => dev.Used && !dev.Related))
				{
					bSkipped = false;
					TuneMsg($"Tuning {device.Device}");
					double maxmin = -1.0;
					if (!MaxMinTune2(stage, device, related: false, out maxmin))
					{
						TuneMsg("Scan error.");
						TuneFinish(error: true);
						return;
					}
					if (maxmin != -1.0)
					{
						SetDeviceValue(device.Id, device.BestValue);
						string msg = device.Device + ":" + device.BestValue.ToString("F2");
						TuneMsg(msg);
					}
					else
					{
						SetDeviceValue(device.Id, device.DefaultValue);
						string msg2 = device.Device + ":" + device.DefaultValue.ToString("F2");
						TuneMsg(msg2);
					}
				}
			}
		}
		TuneFinish(error: false);
	}

	private void TuneKED()
	{
		TuneStage stage = Stages[0];
		TuneMsg($"Stage:{stage.StageName}");
		DeviceCondition deviceCol = Stages[0].Devices.Find((DeviceCondition r) => r.Id == 16);
		DeviceCondition deviceF = Stages[0].Devices.Find((DeviceCondition r) => r.Id == 6);
		DeviceCondition deviceDA = Stages[0].Devices.Find((DeviceCondition r) => r.Id == 12);
		DeviceCondition deviceQE = Stages[0].Devices.Find((DeviceCondition r) => r.Id == 9);
		TuneMsg(string.Format("{0} set to {1:0.00}", Lang.Txt("FormConfig.Columns.Hexapole.Text"), -12));
		LensManager.x2lens.Pole = -12.0;
		TuneMsg(string.Format("{0} set to {1:0.00}", Lang.Txt("FormConfig.Columns.QuadPole.Text"), -10));
		RFManager.rfs.quadPole = -10f;
		TuneMsg(string.Format("{0} set to {1:0.00}", Lang.Txt("FormQuad.PreBias.Text"), -10));
		RFManager.rfs.prePole = -10f;
		InitScanDatas(stage);
		for (double deviceSets = deviceCol.MinValue * (double)deviceCol.Coe; deviceSets <= deviceCol.MaxValue * (double)deviceCol.Coe; deviceSets += deviceCol.Step * (double)deviceCol.Coe)
		{
			SetDeviceValue(deviceCol.Id, deviceSets);
			TuneMsg($"{deviceCol.Device} set to {deviceSets:0.00}");
			deviceCol.BestValue = deviceSets;
			Dictionary<double, double> results = new Dictionary<double, double>();
			for (double FSets = deviceF.MinValue; FSets * (double)deviceF.Coe <= deviceF.MaxValue * (double)deviceF.Coe; FSets += deviceF.Step * (double)deviceF.Coe)
			{
				if (TuneDevice(stage, deviceF, FSets))
				{
					results.Add(FSets, stage.Params.Find((ParamConditon p) => p.Type == 3 || p.Type == 4).Result);
				}
				if (!stage.Params.Where((ParamConditon p) => p.Type == 1 || p.Type == 2).First().Pass || !stage.Params.Where((ParamConditon p) => p.Type == 3 || p.Type == 4).First().Pass)
				{
					continue;
				}
				deviceQE.BestValue = LensManager.x2lens.ReadQE;
				deviceDA.BestValue = LensManager.x2lens.ReadDA;
				foreach (ParamConditon param2 in stage.Params)
				{
					param2.BestResult = param2.Result;
				}
				TuneFinish(error: false);
				return;
			}
			double bestvalue = results.Where((KeyValuePair<double, double> r) => r.Value == results.Values.Max()).First().Key;
			SetDeviceValue(deviceF.Id, bestvalue);
			deviceF.BestValue = bestvalue;
			TuneMsg($"{deviceF.Device} set to {bestvalue:0.00}");
			List<double> DAs = new List<double>();
			List<double> DAResults = new List<double>();
			for (double QESets = deviceQE.MinValue; QESets * (double)deviceQE.Coe <= deviceQE.MaxValue * (double)deviceQE.Coe; QESets += deviceQE.Step * (double)deviceQE.Coe)
			{
				SetDeviceValue(deviceQE.Id, QESets);
				TuneMsg($"{deviceQE.Device} set to {QESets:0.00}");
				DAs.Clear();
				DAResults.Clear();
				for (double DASets = deviceDA.MinValue; DASets * (double)deviceDA.Coe <= deviceDA.MaxValue * (double)deviceDA.Coe; DASets += deviceDA.Step * (double)deviceDA.Coe)
				{
					if (!TuneDevice(stage, deviceDA, DASets))
					{
						continue;
					}
					if (stage.Params.Where((ParamConditon p) => p.Type == 1 || p.Type == 2).First().Pass && stage.Params.Where((ParamConditon p) => p.Type == 3 || p.Type == 4).First().Pass)
					{
						deviceQE.BestValue = QESets;
						deviceDA.BestValue = DASets;
						foreach (ParamConditon param in stage.Params)
						{
							param.BestResult = param.Result;
						}
						TuneFinish(error: false);
						return;
					}
					DAs.Add(DASets);
					DAResults.Add(stage.Params.Where((ParamConditon p) => p.Type == 1 || p.Type == 2).First().Result);
				}
				int index = DAResults.FindIndex((double r) => r == DAResults.Max());
				if (index != -1)
				{
					deviceDA.BestValue = DAs[index];
				}
				deviceDA.MinValue = deviceDA.BestValue - deviceDA.Step * 2.0 * (double)deviceDA.Coe;
				if (Math.Abs(deviceDA.MinValue) < Math.Abs(deviceDA.MinLimit))
				{
					deviceDA.MinValue = deviceDA.MinLimit;
				}
				deviceDA.MaxValue = deviceDA.BestValue + deviceDA.Step * 2.0 * (double)deviceDA.Coe;
				if (Math.Abs(deviceDA.MaxValue) > Math.Abs(deviceDA.MaxLimit))
				{
					deviceDA.MaxValue = deviceDA.MaxLimit;
				}
			}
		}
		TuneFinish(error: true);
	}

	private void TuneKED1()
	{
		TuneStage stage1 = Stages[0];
		TuneStage stage2 = Stages[1];
		TuneStage stage3 = Stages[2];
		DeviceCondition deviceHex = stage3.Devices.Find((DeviceCondition r) => r.Id == 10);
		DeviceCondition deviceDev = stage3.Devices.Find((DeviceCondition r) => r.Id == 21);
		DeviceCondition deviceQuad = stage3.Devices.Find((DeviceCondition r) => r.Id == 18);
		DeviceCondition devicePre = stage3.Devices.Find((DeviceCondition r) => r.Id == 19);
		TuneMsg($"Stage:{stage3.StageName}");
		DeviceCondition device = stage1.Devices.Find((DeviceCondition r) => r.Id == 16);
		for (double deviceSets = device.MinValue * (double)device.Coe; deviceSets <= device.MaxValue * (double)device.Coe; deviceSets += device.Step * (double)device.Coe)
		{
			SetDeviceValue(device.Id, deviceSets);
			TuneMsg($"{device.Device} set to {deviceSets:0.00}");
			SetDeviceValue(deviceQuad.Id, -9.0);
			TuneMsg(string.Format("{0} set to {1:0.00}", Lang.Txt("FormConfig.Columns.QuadPole.Text"), -9));
			SetDeviceValue(devicePre.Id, -9.0);
			TuneMsg(string.Format("{0} set to {1:0.00}", Lang.Txt("FormQuad.PreBias.Text"), -9));
			SetDeviceValue(deviceHex.Id, -10.0);
			TuneMsg(string.Format("{0} set to {1:0.00}", Lang.Txt("FormConfig.Columns.Hexapole.Text"), -10));
			DeviceCondition deviceFocus = stage2.Devices.FindAll((DeviceCondition r) => r.Used)[0];
			InitScanDatas(stage2);
			Dictionary<double, double> results = new Dictionary<double, double>();
			for (double FSets = deviceFocus.MinValue; FSets * (double)deviceFocus.Coe <= deviceFocus.MaxValue * (double)deviceFocus.Coe; FSets += deviceFocus.Step * (double)deviceFocus.Coe)
			{
				if (TuneDevice(stage2, deviceFocus, FSets))
				{
					results.Add(FSets, stage2.Params.Find((ParamConditon p) => p.Type == 1).Result);
					if (stage2.Params.Where((ParamConditon p) => p.Type == 1 || p.Type == 2).First().Pass && stage2.Params.Where((ParamConditon p) => p.Type == 3 || p.Type == 4).First().Pass)
					{
						deviceHex.BestValue = -10.0;
						deviceQuad.BestValue = -9.0;
						devicePre.BestValue = -9.0;
						deviceFocus.BestValue = FSets;
						device.BestValue = deviceSets;
						TuneFinish(error: false);
						return;
					}
				}
			}
			double bestvalue = results.Where((KeyValuePair<double, double> r) => r.Value == results.Values.Max()).First().Key;
			SetDeviceValue(deviceFocus.Id, bestvalue);
			deviceFocus.BestValue = bestvalue;
			TuneMsg($"{deviceFocus.Device} set to {bestvalue:0.00}");
			if (FindBestResultforKED(stage3))
			{
				device.BestValue = deviceSets;
				deviceFocus.BestValue = LensManager.x2lens.ReadF;
				TuneFinish(error: false);
				break;
			}
		}
	}

	private bool FindBestResultforKED(TuneStage stage)
	{
		DeviceCondition deviceHex = stage.Devices.Find((DeviceCondition r) => r.Id == 10);
		DeviceCondition deviceDev = stage.Devices.Find((DeviceCondition r) => r.Id == 21);
		DeviceCondition deviceQuad = stage.Devices.Find((DeviceCondition r) => r.Id == 18);
		DeviceCondition devicePre = stage.Devices.Find((DeviceCondition r) => r.Id == 19);
		for (double deviceSets = deviceHex.MinValue; deviceSets * (double)deviceHex.Coe <= deviceHex.MaxValue * (double)deviceHex.Coe; deviceSets += deviceHex.Step * (double)deviceHex.Coe)
		{
			SetDeviceValue(deviceHex.Id, deviceSets);
			TuneMsg($"{deviceHex.Device} set to {deviceSets:0.00}");
			for (double DevSets = deviceDev.MinValue * (double)deviceDev.Coe; DevSets <= deviceDev.MaxValue * (double)deviceDev.Coe; DevSets += deviceDev.Step * (double)deviceDev.Coe)
			{
				double quadBias = DevSets + deviceSets;
				if (!(quadBias * (double)deviceQuad.Coe >= deviceQuad.MinLimit * (double)deviceQuad.Coe) || !(quadBias * (double)deviceQuad.Coe <= deviceQuad.MaxLimit * (double)deviceQuad.Coe))
				{
					continue;
				}
				SetDeviceValue(deviceQuad.Id, quadBias);
				TuneMsg($"{deviceQuad.Device} set to {quadBias:0.00}");
				for (double preSets = devicePre.MinValue; preSets * (double)devicePre.Coe <= devicePre.MaxValue * (double)devicePre.Coe; preSets += devicePre.Step * (double)devicePre.Coe)
				{
					if (TuneDevice(stage, devicePre, preSets) && stage.Params.Where((ParamConditon p) => p.Type == 1 || p.Type == 2).First().Pass && stage.Params.Where((ParamConditon p) => p.Type == 3 || p.Type == 4).First().Pass)
					{
						deviceHex.BestValue = deviceSets;
						deviceQuad.BestValue = quadBias;
						devicePre.BestValue = preSets;
						return true;
					}
				}
			}
		}
		return false;
	}

	private bool TuneToGetBestValue(TuneStage stage, DeviceCondition device, bool related, out double bestValue)
	{
		bestValue = -1.0;
		ParamConditon tunePara = stage.Params.Where((ParamConditon para) => para.Type == 1 || para.Type == 2).First();
		List<double> devValues = new List<double>();
		List<double> paraValues = new List<double>();
		double step = device.Step;
		double tmp1 = device.DefaultValue * (double)device.Coe;
		double tmp2 = tmp1 + step;
		devValues.Add(tmp1 * (double)device.Coe);
		devValues.Add(tmp2 * (double)device.Coe);
		for (int i = 0; i < devValues.Count; i++)
		{
			if (!TuneDevice(stage, device, devValues[i]))
			{
				return false;
			}
			if (Vacuum.vacumm.ReadMode != 5)
			{
				return false;
			}
			paraValues.Add(tunePara.Result);
			List<double> result = new List<double>();
			List<DeviceCondition> devs = stage.Devices.Where((DeviceCondition r) => r.Used).ToList();
			for (int j = 0; j < devs.Count(); j++)
			{
				result.Add(ReadPosition(devs[j]));
			}
			result.Add(tunePara.Result);
			StageDeviceResult.Add(result);
		}
		int maxminIdx = MaxMinIndex(paraValues.ToArray(), tunePara.Type == 1);
		device.BestValue = devValues[maxminIdx];
		device.BestResult = paraValues[maxminIdx];
		tunePara.BestResult = paraValues[maxminIdx];
		bestValue = paraValues[maxminIdx];
		return true;
	}

	private bool MaxMinTune2(TuneStage stage, DeviceCondition device, bool related, out double bestValue)
	{
		bestValue = -1.0;
		ParamConditon tunePara = stage.Params.Where((ParamConditon para) => para.Type == 1 || para.Type == 2).First();
		List<double> devValues = new List<double>();
		List<double> paraValues = new List<double>();
		double step = device.Step;
		for (double tmp = device.MinValue * (double)device.Coe; tmp <= device.MaxValue * (double)device.Coe; tmp += step)
		{
			devValues.Add(tmp * (double)device.Coe);
		}
		for (int i = 0; i < devValues.Count; i++)
		{
			if (!TuneDevice(stage, device, devValues[i]))
			{
				return false;
			}
			if (Vacuum.vacumm.ReadMode != 5)
			{
				return false;
			}
			paraValues.Add(tunePara.Result);
			List<double> result = new List<double>();
			List<DeviceCondition> devs = stage.Devices.Where((DeviceCondition r) => r.Used).ToList();
			for (int j = 0; j < devs.Count(); j++)
			{
				result.Add(ReadPosition(devs[j]));
			}
			result.Add(tunePara.Result);
			StageDeviceResult.Add(result);
			if (paraValues.Count >= 7)
			{
				int count = paraValues.Count();
				if ((paraValues[count - 1] < paraValues[count - 2] && paraValues[count - 2] < paraValues[count - 3] && paraValues[count - 3] < paraValues[count - 4] && paraValues[count - 5] < paraValues[count - 4] && paraValues[count - 6] < paraValues[count - 5] && paraValues[count - 7] < paraValues[count - 6] && tunePara.Type == 1) || (paraValues[count - 1] > paraValues[count - 2] && paraValues[count - 2] > paraValues[count - 3] && paraValues[count - 3] > paraValues[count - 4] && paraValues[count - 5] > paraValues[count - 4] && paraValues[count - 6] > paraValues[count - 5] && paraValues[count - 7] > paraValues[count - 6] && tunePara.Type == 2))
				{
					break;
				}
			}
			if (bSkipped)
			{
				break;
			}
		}
		int maxminIdx = MaxMinIndex(paraValues.ToArray(), tunePara.Type == 1);
		device.BestValue = devValues[maxminIdx];
		device.BestResult = paraValues[maxminIdx];
		tunePara.BestResult = paraValues[maxminIdx];
		bestValue = paraValues[maxminIdx];
		return true;
	}

	public void TunePoinSend(double x, double y, double z, double intensity)
	{
		if (this.EventPointMsg != null)
		{
			this.EventPointMsg(null, new PointEventMsg(x, y, z, intensity));
		}
	}

	private void TuneFinish(bool error)
	{
		TuneSucceed = !error;
		if (this.EventTuneFinish != null)
		{
			this.EventTuneFinish(null, null);
		}
	}

	private void TuneMsg(string msg)
	{
		if (this.EventTuneMsg != null)
		{
			this.EventTuneMsg(null, new MsgEventArgs(msg));
		}
	}

	private int MaxMinIndex(double[] datas, bool max)
	{
		int idx = 0;
		for (int i = 1; i < datas.Length; i++)
		{
			idx = (max ? ((datas[idx] > datas[i]) ? idx : i) : ((datas[idx] < datas[i]) ? idx : i));
		}
		return idx;
	}

	private bool TuneDevice(TuneStage stage, DeviceCondition device, double value)
	{
		TuneMsg($"{device.Device} set to {value:0.00}");
		SetDeviceValue(device.Id, value);
		device.DeviceSets = value;
		int count = 0;
		while (!CheckPosition(value, device))
		{
			count++;
			Thread.Sleep(1000);
			if (count >= 15)
			{
				return false;
			}
		}
		Thread.Sleep(2000);
		List<int> res = new List<int>();
		for (int j = 0; j < massX.Count; j++)
		{
			res.Add(1);
		}
		for (int i = 0; i < stage.Sweeps; i++)
		{
			if (i == 0)
			{
				Detector.Instance.SetMassAxis(massX.ToArray());
			}
			Detector.Instance.SendHopDatas(massX.ToArray(), res.ToArray(), true, false);
			if (!scanEvent.WaitOne(30000))
			{
				return false;
			}
		}
		CalculateResults(stage, device, value);
		return true;
	}

	private void CalculateResults(TuneStage stage, DeviceCondition device, double value)
	{
		double[] mass = Detector.msDetectorPara.MassAxis.ToArray();
		double[] intensity = Detector.msDetectorPara.IntesnsityPulse.ToArray();
		string point = "";
		List<DeviceCondition> devs = stage.Devices.Where((DeviceCondition r) => r.Used).ToList();
		if (Name == "KED")
		{
			devs = stage.Devices;
		}
		for (int i = 0; i < devs.Count; i++)
		{
			point += ReadPosition(devs[i]).ToString("F2");
			point += ",";
		}
		foreach (ParamConditon para2 in stage.Params.Where((ParamConditon p) => p.Type != 0))
		{
			string ss = "point:";
			if (para2.Isotope != null)
			{
				para2.Result = intensity.Where((double data, int index) => mass[index] >= para2.Isotope.Mass - 0.1 && mass[index] <= para2.Isotope.Mass + 0.1).Average();
				para2.Result /= stage.Sweeps;
				ss = ss + para2.Isotope.Symbol.ToString() + ":";
			}
			else if (para2.Ratio != null)
			{
				double numerator = intensity.Where((double data, int index) => mass[index] >= para2.Ratio.Numerator.Mass - 0.1 && mass[index] <= para2.Ratio.Numerator.Mass + 0.1).Average();
				double denominator = intensity.Where((double data, int index) => mass[index] >= para2.Ratio.Denominator.Mass - 0.1 && mass[index] <= para2.Ratio.Denominator.Mass + 0.1).Average();
				para2.Result = numerator / denominator;
				ss = ss + $"{para2.Ratio.Numerator.Symbol}/{para2.Ratio.Denominator.Symbol}" + ":";
			}
			if ((para2.Type == 1 || para2.Type == 3) && para2.Result < para2.Limit)
			{
				para2.Pass = false;
			}
			else if ((para2.Type == 2 || para2.Type == 4) && para2.Result > para2.Limit)
			{
				para2.Pass = false;
			}
			else
			{
				para2.Pass = true;
			}
			ss = ss + point + para2.Result.ToString("F2");
			TuneMsg(ss);
			TuneMsg(string.Format("Result for {0} = {1:0.000} ({2})", para2.Symbol, para2.Result, para2.Pass ? "Pass" : "Fail"));
		}
		if (stage.Params.Exists((ParamConditon para) => para.Type != 0 && !para.Pass))
		{
			return;
		}
		foreach (ParamConditon param in stage.Params)
		{
			param.BestResult = param.Result;
		}
	}

	private void InitScanDatas(TuneStage stage)
	{
		massX.Clear();
		List<TuneIsotope> isotopes = new List<TuneIsotope>();
		foreach (ParamConditon para in stage.Params.Where((ParamConditon p) => p.Type != 0))
		{
			if (para.Isotope != null)
			{
				isotopes.Add(para.Isotope);
			}
			else if (para.Ratio != null)
			{
				TuneIsotope numerator = para.Ratio.Numerator;
				TuneIsotope denominator = para.Ratio.Denominator;
				if (!isotopes.Contains(numerator))
				{
					isotopes.Add(numerator);
				}
				if (!isotopes.Contains(denominator))
				{
					isotopes.Add(denominator);
				}
			}
		}
		foreach (TuneIsotope isotope in isotopes)
		{
			massX.Add(isotope.Mass);
		}
	}

	private void SetDeviceValue(int id, double value)
	{
		switch (id)
		{
		case 0:
			PlatManager.plat.X = (float)value;
			Plasma.Instance.SetXAxis();
			break;
		case 1:
			PlatManager.plat.Z = (float)value;
			Plasma.Instance.SetZAxis();
			break;
		case 2:
			PlatManager.plat.Y = (float)value;
			Plasma.Instance.SetYAxis();
			break;
		case 3:
			LensManager.x2lens.Ex = value;
			LensManager.Instance.X2_SetEx();
			break;
		case 4:
			LensManager.x2lens.L1 = value;
			LensManager.Instance.X2_SetL1();
			break;
		case 5:
			LensManager.x2lens.L2 = value;
			LensManager.Instance.X2_SetL2();
			break;
		case 6:
			LensManager.x2lens.F = value;
			LensManager.Instance.X2_SetF();
			break;
		case 7:
			LensManager.x2lens.D1 = value;
			LensManager.Instance.X2_SetD1();
			break;
		case 8:
			LensManager.x2lens.D2 = value;
			LensManager.Instance.X2_SetD2();
			break;
		case 9:
			LensManager.x2lens.QE = value;
			LensManager.Instance.X2_SetQE();
			break;
		case 10:
			LensManager.x2lens.Pole = value;
			LensManager.Instance.X2_SetPole();
			break;
		case 11:
			LensManager.x2lens.L3 = value;
			LensManager.Instance.X2_SetL3();
			break;
		case 12:
			LensManager.x2lens.DA = value;
			LensManager.Instance.X2_SetDA();
			break;
		case 13:
			PlasmaManager.plasma.Nebuliser = value;
			Plasma.Instance.OpenNebulizerGas();
			break;
		case 14:
			PlasmaManager.plasma.Cool = value;
			Plasma.Instance.OpenCoolGas();
			break;
		case 15:
			PlasmaManager.plasma.Auxiliary = value;
			Plasma.Instance.OpenAuxiliaryGas();
			break;
		case 16:
			if (Collision.Instance.CRCType == 1)
			{
				PlasmaManager.plasma.Collision = value;
				Plasma.Instance.OpenCollision();
				break;
			}
			PlasmaManager.plasma.Collision = value;
			Plasma.Instance.OpenCollision();
			PlasmaManager.plasma.Collision2 = value;
			Plasma.Instance.OpenCollision2();
			break;
		case 17:
			PlasmaManager.plasma.Power = value;
			Plasma.Instance.SetPower();
			break;
		case 21:
			RFManager.rfs.quadPole = (float)(value + LensManager.x2lens.Pole);
			if (Detector.detectorConfig.IsNewDetector)
			{
				Detector.Instance.msDetectorRF.SetQuadPoleNew();
			}
			else
			{
				Detector.Instance.msDetectorRF.SetQuadPole();
			}
			break;
		case 19:
			RFManager.rfs.prePole = (float)value;
			if (Detector.detectorConfig.IsNewDetector)
			{
				Detector.Instance.msDetectorRF.SetPrePoleNew();
			}
			else
			{
				Detector.Instance.msDetectorRF.SetPrePole();
			}
			break;
		case 18:
			RFManager.rfs.quadPole = (float)value;
			if (Detector.detectorConfig.IsNewDetector)
			{
				Detector.Instance.msDetectorRF.SetQuadPoleNew();
			}
			else
			{
				Detector.Instance.msDetectorRF.SetQuadPole();
			}
			break;
		case 20:
			RFManager.rfs.hexPara = (float)value;
			break;
		}
	}
}
